package de.stefanocke.roo.wicket.templates

import de.stefanocke.roo.wicket.Stereotypes
import de.stefanocke.roo.wicket.RooFactoryMethod

class DetailsTemplate extends JavaHtmlTemplate{
	
	override String javaClassNameWhenNew(){
		"DetailsPanel"
	}
	
	override String stereotype(){
		Stereotypes::DETAILS
	}
	
	override subPackageToUseWhenNew(){
		"common"
	}
		
	override buildJavaContents(){
		import_("java.util.Calendar")
		import_("java.util.Date")
		import_("java.util.List")
		
		import_("org.apache.wicket.Component")
		import_("org.apache.wicket.MarkupContainer")
		import_("org.apache.wicket.datetime.markup.html.basic.DateLabel")
		import_("org.apache.wicket.markup.html.WebMarkupContainer")
		import_("org.apache.wicket.markup.html.basic.EnumLabel")
		import_("org.apache.wicket.markup.html.basic.Label")
		import_("org.apache.wicket.markup.html.list.ListItem")
		import_("org.apache.wicket.markup.html.list.ListView")
		import_("org.apache.wicket.markup.html.panel.Fragment")
		import_("org.apache.wicket.markup.html.panel.Panel")
		import_("org.apache.wicket.model.AbstractReadOnlyModel")
		import_("org.apache.wicket.model.CompoundPropertyModel")
		import_("org.apache.wicket.model.IModel")
		import_("org.apache.wicket.model.ResourceModel")
		import_("org.springframework.format.annotation.DateTimeFormat")
		
		val ILabeled = import_(typeof(ILabeledTemplate).generatedJavaType)
		val DecoratorFragment = import_(typeof(DecoratorFragmentTemplate).generatedJavaType)
		
		import_(typeof(RooFactoryMethod));
		'''	
		«stereotypeAnnotation»
		public abstract class «simpleTypeName»<T> extends Panel implements «ILabeled»{
		
			/***/
			private static final long serialVersionUID = 1L;
		
			/**
			 * The ID for the container providing the CPM.
			 */
			private static final String CPM_CONTAINER_ID = "cpm";
		
			/**
			 * The ID for the label component.
			 */
			private static final String LABEL_ID = "label";
		
			protected «simpleTypeName»() {
				super("INVALID");
				throw new UnsupportedOperationException("Do not use this constructor since it is only a workaround for ITD issues");
			}
		
			public «simpleTypeName»(String id) {
				super(id);
				init();
			}
		
			public «simpleTypeName»(String id, IModel<T> model) {
				super(id, new CompoundPropertyModel<T>(model));	
				init();
			}
		
			protected void init() {
				WebMarkupContainer cpmContainer = new WebMarkupContainer(CPM_CONTAINER_ID);
				Label label = new Label(LABEL_ID, new ResourceModel(getId(),"")); //TODO: By default, it should be something like the name of the entity
				add(label);
				List<Component> fields = createFields();
				cpmContainer.add(fields.toArray(new Component[0]));
				add(cpmContainer);
		
			}
			
			@Override
			public void setLabel(IModel<String> labelModel) {
				get(LABEL_ID).setDefaultModel(labelModel);	
			}
			
			@SuppressWarnings("unchecked")
			@Override
			public IModel<String> getLabel() {
				return (IModel<String>) get(LABEL_ID).getDefaultModel();
			}
			
			@Override
			protected void onInitialize() {
				super.onInitialize();
				
				onModelChanged();
			}
		
			@SuppressWarnings("unchecked")
			@Override
			protected void onModelChanged() {
				IModel<T> model = (IModel<T>) getDefaultModel();
				get(CPM_CONTAINER_ID).setDefaultModel(new CompoundPropertyModel<T>(model));
				super.onModelChanged();
			}
			
			protected abstract List<Component> createFields();
			
			/**
			 * Gets model object
			 * 
			 * @return model object
			 */
			@SuppressWarnings("unchecked")
			public final T getModelObject()	{
				return (T)getDefaultModelObject();
			}
			
			/**
			 * Gets model 
			 * 
			 * @return model 
			 */
			@SuppressWarnings("unchecked")
			public final CompoundPropertyModel<T> getModel(){
				return (CompoundPropertyModel<T>)getDefaultModel();
			}
			
			@RooStereotype("wicket.ListView")
			public static abstract class ListField<T> extends ComplexField{
		
				/***/
				private static final long serialVersionUID = 1L;
		
				public ListField(String id, MarkupContainer markupProvider) {
					super(id, markupProvider);
				}
				
				@Override
				protected Component createComponent(String id, MarkupContainer markupProvider) {
					return new ListViewFragment<T>(id, markupProvider) {
						
						/***/
						private static final long serialVersionUID = 1L;
		
		
						@Override
						protected Component createItemComponent(String id) {
							return ListField.this.createItemComponent(id);
						}
		
						
						protected String getItemLabel(final ListItem<T> item) {
							// TODO: It is very implicit to assume the parent provides the item
							// label...
							return getLocalizer().getString(ListField.this.getId(), ListField.this) + " " + (item.getIndex() + 1);
						}
		
		
						@Override
						protected IModel<String> getItemLabelModel(final ListItem<T> item) {
							
								return new AbstractReadOnlyModel<String>() {
		
									/***/
									private static final long serialVersionUID = 1L;
		
									@Override
									public String getObject() {
										return getItemLabel(item);
									}
		
								};
		
						}
						
					};
				}
		
				protected abstract Component createItemComponent(String id);
				
				
				
			}
			
			public static abstract class ListViewFragment<T> extends Fragment{
		
				/***/
				private static final long serialVersionUID = 1L;
		
				public ListViewFragment(String id, MarkupContainer markupProvider) {
					super(id, "listFragment", markupProvider);
					add(new ListView<T>("list"){
		
						/***/
						private static final long serialVersionUID = 1L;
		
						@Override
						protected void populateItem(ListItem<T> item) {
							Component itemComponent = createItemComponent("item");
							itemComponent.setDefaultModel(item.getModel());
							if (itemComponent instanceof «ILabeled») {
								((«ILabeled») itemComponent).setLabel(getItemLabelModel(item));
							}
							
							item.add(itemComponent);
						}
						
					});
				}
				
				protected abstract IModel<String> getItemLabelModel(ListItem<T> item);
				
				@Override
				protected void onInitialize() {
					super.onInitialize();
					onModelChanged();
				}
				
				@Override
				protected void onModelChanged() {
					super.onModelChanged();
					get("list").setDefaultModel(getDefaultModel());
				}
				
				protected abstract Component createItemComponent(String id);
				
			}
			
			public static abstract class SimpleField extends «DecoratorFragment»<Component>{
		
				/***/
				private static final long serialVersionUID = 1L;
		
				public SimpleField(String id, MarkupContainer markupProvider) {
					super(id, "simpleField", markupProvider);
				}
				
			}
			
			public static abstract class ComplexField extends «DecoratorFragment»<Component>{
		
				/***/
				private static final long serialVersionUID = 1L;
		
				public ComplexField(String id, MarkupContainer markupProvider) {
					super(id, "complexField", markupProvider);
				}
				
			}
			
		
			@RooFactoryMethod(modelClasses = { Calendar.class, Date.class })
			protected SimpleField createDateLabelDecorated(String id, final DateTimeFormat format) {
				return new SimpleField(id, this) {
					
					/***/
					private static final long serialVersionUID = 1L;
		
					@Override
					protected Component createComponent(String id) {	
						return createDateLabel(id, format);
					}
				};
			}
			
			protected DateLabel createDateLabel(String id, DateTimeFormat format) {
				if (format != null) {
					if (!format.pattern().isEmpty()) {
						return DateLabel.forDatePattern(id, format.pattern());
					} else {
						return DateLabel.forDateStyle(id, format.style());
					}
				} else {
					return DateLabel.forDateStyle(id, "SS");
				}
			}
		
			@RooFactoryMethod(modelClasses = Enum.class)
			protected SimpleField createEnumLabelDecorated(String id){
				return new SimpleField(id, this) {
					
					/***/
					private static final long serialVersionUID = 1L;
		
					@Override
					protected Component createComponent(String id) {
						return createEnumLabel(id);
					}
				};
			}
			protected <E extends Enum<E>> EnumLabel<E> createEnumLabel(String id) {
				return new EnumLabel<E>(id);
			}
		
		//	@RooFactoryMethod(modelClasses = Boolean.class)
		//	protected Label createBooleanLabel(String id) {
		//		return new Label(id);
		//	}
		
			@RooFactoryMethod
			protected SimpleField createStringLabelDecorated(String id) {
				return new SimpleField(id, this) {
					
					/***/
					private static final long serialVersionUID = 1L;
		
					@Override
					protected Component createComponent(String id) {
						return createStringLabel(id);
					}
				};
			}
			
			protected Label createStringLabel(String id) {
				return new Label(id);
			}
		}
		'''
	}
	
	override buildHtmlBody(){
		'''
		<wicket:panel>
			<fieldset>
			<legend wicket:id="label"></legend>
				<div class="fieldset">
					<wicket:container wicket:id="cpm">		
						<wicket:child />
					</wicket:container>
				</div>
		    </fieldset>		
		</wicket:panel>
		
		<wicket:fragment wicket:id="listFragment">	
			<span wicket:id="list">				
				<span wicket:id="item"></span>					
			</span>
		</wicket:fragment>
		
		<wicket:fragment wicket:id="simpleField">
			<div class="field">
				<label wicket:id="label" class="fieldlabel">field label</label>
				<span wicket:id="comp"/>		
			</div>
		</wicket:fragment>
		
		<wicket:fragment wicket:id="complexField">
			<div>
				<fieldset>
					<legend wicket:id="label"></legend>
					<div class="fieldset">
						<wicket:container wicket:id="comp"/>
					</div>
				</fieldset>
			</div>
		</wicket:fragment>
		'''
	}
}